package com.von.nhcf.mvc.config;

import com.github.pagehelper.PageInfo;
import com.google.gson.Gson;
import com.von.nhcf.constant.NhcfConstant;
import com.von.nhcf.entity.Admin;
import com.von.nhcf.exception.AccessIllegalException;
import com.von.nhcf.exception.AdminOnlineProjectException;
import com.von.nhcf.exception.LoginAcctAlreadyExistedException;
import com.von.nhcf.exception.LoginFailureException;
import com.von.nhcf.service.AdminService;
import com.von.nhcf.util.RequestTypeAnalysisUtil;
import com.von.nhcf.util.ResultEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

/**
 * 异常处理类
 * @author von
 */
@ControllerAdvice
public class NhcfExceptionResolver {
    /**
     * 注册已存在的账户处理方法
     * @param exception : 异常对象，为了获取异常描述信息
     * @param request   : servlet请求
     * @param response  : servlet 响应
     * @return ModelAndView
     */
    @ExceptionHandler(value = LoginAcctAlreadyExistedException.class)
    public ModelAndView resolveLoginAcctAlreadyExistedException(LoginAcctAlreadyExistedException exception, HttpServletRequest request,
                                                     HttpServletResponse response) throws IOException {
        // 异常信息回显页面
        String resolveView = "admin_add";
        return commonResolveException(exception, request, response, resolveView);
    }
    @Autowired
    AdminService adminService;
    /**
     * 管理员在线保护异常处理方法
     * @param exception : 异常对象，为了获取异常描述信息
     * @param request   : servlet请求
     * @param response  : servlet 响应
     * @return ModelAndView
     */
    @ExceptionHandler(value = AdminOnlineProjectException.class)
    public ModelAndView resolveAdminOnlineProjectException(AdminOnlineProjectException exception, HttpServletRequest request,
                                                     HttpServletResponse response) throws IOException {
        // 获取异常处理页面
        String resolveView = "admin_page";
        // 获取pageInfo
        String keyword = (String)request.getAttribute("keyword");
        Integer pageSize = (Integer)request.getAttribute("pageSize");
        Integer pageNum = (Integer)request.getAttribute("pageNum");
        PageInfo<Admin> pageInfo = adminService.getPageInfo(keyword, pageNum, pageSize);
        request.setAttribute(NhcfConstant.ATTR_NAME_PAGE_INFO, pageInfo);
        return commonResolveException(exception, request, response, resolveView);
    }
    /**
     * 登录异常处理方法
     * @param exception : 异常对象，为了获取异常描述信息
     * @param request   : servlet请求
     * @param response  : servlet 响应
     * @return ModelAndView
     */
    @ExceptionHandler(value = LoginFailureException.class)
    public ModelAndView resolveLoginFailureException(LoginFailureException exception, HttpServletRequest request,
                                                     HttpServletResponse response) throws IOException {
        // 异常处理页面
        String resolveView = "admin_login";
        return commonResolveException(exception, request, response, resolveView);
    }
    /**
     * 核心异常处理方法
     *
     * @param exception SpringMVC 捕获到的异常对象
     * @param request   为了判断当前请求是“普通请求”还是“Ajax 请求”，需要传入原生 request 对象
     * @param response  为了能够将 JSON 字符串作为当前请求的响应数，据返回给浏览器
     * @param viewName  指定要前往的视图名称
     * @return ModelAndView
     * @throws IOException
     */
    private ModelAndView commonResolveException(Exception exception, HttpServletRequest request,
                                                HttpServletResponse response, String viewName) throws IOException {
        // 判断当前请求是“普通请求”还是“Ajax 请求”
        boolean judgeResult = RequestTypeAnalysisUtil.isAjax(request);
        // 如果是 Ajax 请求
        if (judgeResult) {
            // 从当前异常对象中获取异常信息
            String message = exception.getMessage();
            // 创建 ResultEntity
            ResultEntity<Object> resultEntity = ResultEntity.failureWithMsg(message);
            // 创建 Gson 对象
            Gson gson = new Gson();
            // 将 resultEntity 转化为 JSON 字符串
            String json = gson.toJson(resultEntity);
            // 把当前 JSON 字符串作为当前请求的响应体数据返回给浏览器
            // 获取 Writer 对象
            PrintWriter writer = response.getWriter();
            // 写入数据
            writer.write(json);
            // 返回null， 不给 SpringMVC 提供 ModelAndView 对象
            // 这样SpringMVC 就知道不需要框架解析视图来提供响应，而是程序员自己提供了响应
            return null;
        }
        //创建 ModelAndView 对象
        ModelAndView modelAndView = new ModelAndView();
        // Exception 对象存入模型
        modelAndView.addObject(NhcfConstant.ATTR_NAME_EXCEPTION, exception);
        // pageInfo对象存入模型
        PageInfo<Admin> pageInfo = (PageInfo<Admin>)request.getAttribute(NhcfConstant.ATTR_NAME_PAGE_INFO);
        if(pageInfo != null) {
            modelAndView.addObject(NhcfConstant.ATTR_NAME_PAGE_INFO, pageInfo);
        }
        // 设置目标视图名称
        modelAndView.setViewName(viewName);
        // 返回 ModelAndView 对象
        return modelAndView;
    }
}
